package br.cin.stadium.application.activities;

import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import br.cin.stadium.application.R;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
//import android.hardware.Camera;
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.provider.MediaStore.Video;
import android.text.format.DateFormat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;

public class VideoRecord extends Activity implements SurfaceHolder.Callback,
		MediaRecorder.OnErrorListener, MediaRecorder.OnInfoListener
{
	private static final int	STOP						= 0;
	private static final int	RECORD						= 1;
	private static final int	MAX_RECORDING_DURATION_MS	= 10 * 60 * 1000;
	private static final String	TAG							= "videocamera";
	private static final float	VIDEO_ASPECT_RATIO			= 176.0f / 144.0f;

	private boolean				m_isRecording				= false;
	private Preview				mPreview;
	private ContentValues		mCurrentVideoValues;
	private String				mCameraVideoFilename;
	private MediaRecorder		mMediaRecorder;
	private FileDescriptor		mCameraVideoFileDescriptor;
	private SurfaceHolder		mSurfaceHolder				= null;
	
	static ContentResolver mContentResolver;

	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);

		this.requestWindowFeature(Window.FEATURE_NO_TITLE);

		mContentResolver = getContentResolver();
		
		mPreview = new Preview(this);
		mPreview.setAspectRatio(VIDEO_ASPECT_RATIO);

		SurfaceHolder holder = mPreview.getHolder();
		holder.addCallback(this);
		holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

		this.setContentView(mPreview);
	}
	
	@Override
	public void onResume()
	{
		super.onResume();
		
		this.initializeVideo();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu)
	{
		menu.add(0, RECORD, 0, "Start recording").setIcon(R.drawable.record);
		menu.add(0, STOP, 0, "Stop recording").setIcon(R.drawable.stopblue);

		return true;
	}

	/* Handles item selections */
	public boolean onOptionsItemSelected(MenuItem item)
	{
		switch (item.getItemId())
		{
			case STOP:
				this.StopRecording();
				return true;
			case RECORD:
				if (m_isRecording == false)
				{
					this.StartRecording();
				}
				return true;
		}

		return false;
	}

	private void StopRecording()
	{
		boolean needToRegisterRecording = false;
		if (m_isRecording || mMediaRecorder != null)
		{
			if (m_isRecording && mMediaRecorder != null)
			{
				try
				{
					mMediaRecorder.setOnErrorListener(null);
					mMediaRecorder.setOnInfoListener(null);
					mMediaRecorder.stop();
				}
				catch (RuntimeException e)
				{
					Log.e(TAG, "stop fail: " + e.getMessage());
				}

				Log.v(TAG, "Setting current video filename: " + mCameraVideoFilename);
				needToRegisterRecording = true;
				m_isRecording = false;
			}
			
			releaseMediaRecorder();
		}
		
		if (needToRegisterRecording)
		{
			registerVideo();
		}

		mCameraVideoFilename = null;
		mCameraVideoFileDescriptor = null;
	}

	private void pauseAudioPlayback()
	{
		Intent i = new Intent("com.android.music.musicservicecommand");
		i.putExtra("command", "pause");

		sendBroadcast(i);
	}

	private void StartRecording()
	{
		if (!m_isRecording)
		{
			// Check mMediaRecorder to see whether it is initialized or not.
			if (mMediaRecorder == null && initializeVideo() == false)
			{
				return;
			}

			pauseAudioPlayback();

			try
			{
				mMediaRecorder.setOnErrorListener(this);
				mMediaRecorder.setOnInfoListener(this);
				mMediaRecorder.start(); // Recording is now started
			}
			catch (RuntimeException e)
			{
				Log.e(TAG, "Could not start media recorder. ", e);
				return;
			}

			m_isRecording = true;
		}
	}

	private void releaseMediaRecorder()
	{
		if (mMediaRecorder != null)
		{
			cleanupEmptyFile();
			mMediaRecorder.reset();
			mMediaRecorder.release();
			mMediaRecorder = null;
		}
	}

	private void registerVideo()
	{
		if (mCameraVideoFileDescriptor == null)
		{
			Uri videoTable = Uri.parse("content://media/external/video/media");
			mContentResolver.insert(videoTable,	mCurrentVideoValues);
		}
		
		mCurrentVideoValues = null;
	}

	private void cleanupEmptyFile()
	{
		if (mCameraVideoFilename != null)
		{
			File f = new File(mCameraVideoFilename);
			if (f.length() == 0 && f.delete())
			{
				mCameraVideoFilename = null;
			}
		}
	}

	private void createVideoPath()
	{
		long dateTaken = System.currentTimeMillis();

		String title = createName(dateTaken);
		String displayName = title + ".3gp"; // Used when emailing.
		String cameraDirPath = Environment.getExternalStorageDirectory().toString()	+ "/DCIM/Camera";

		File cameraDir = new File(cameraDirPath);
		cameraDir.mkdirs();

		SimpleDateFormat dateFormat = new SimpleDateFormat("'video'-yyyy-MM-dd-HH-mm-ss");

		Date date = new Date(dateTaken);

		String filepart = dateFormat.format(date);
		String filename = cameraDirPath + "/" + filepart + ".3gp";

		ContentValues values = new ContentValues(7);

		values.put(Video.Media.TITLE, title);
		values.put(Video.Media.DISPLAY_NAME, displayName);
		values.put(Video.Media.DESCRIPTION, "");
		values.put(Video.Media.DATE_TAKEN, dateTaken);
		values.put(Video.Media.MIME_TYPE, "video/3gpp");
		values.put(Video.Media.DATA, filename);

		mCameraVideoFilename = filename;
		mCurrentVideoValues = values;
	}

	static private String createName(long dateTaken)
	{
		return DateFormat.format("yyyy-MM-dd kk.mm.ss", dateTaken).toString();
	}

	private boolean initializeVideo()
	{
		Intent intent = getIntent();
		// Bundle myExtras = intent.getExtras();

		releaseMediaRecorder();

		if (mSurfaceHolder == null)
		{
			return false;
		}

		mMediaRecorder = new MediaRecorder();

		//mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
		mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
		mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);

		mMediaRecorder.setMaxDuration(MAX_RECORDING_DURATION_MS);

		createVideoPath();
		mMediaRecorder.setOutputFile(mCameraVideoFilename);

		boolean videoQualityHigh = false;

		if (intent.hasExtra(MediaStore.EXTRA_VIDEO_QUALITY))
		{
			int extraVideoQuality = intent.getIntExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0);
			videoQualityHigh = (extraVideoQuality > 0);
		}

		// Use the same frame rate for both, since internally
		// if the frame rate is too large, it can cause camera to become
		// unstable. We need to fix the MediaRecorder to disable the support
		// of setting frame rate for now.
		mMediaRecorder.setVideoFrameRate(20);
		if (videoQualityHigh)
		{
			mMediaRecorder.setVideoSize(352, 288);
		}
		else
		{
			mMediaRecorder.setVideoSize(176, 144);
		}

		mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263);
		// if (!DEBUG_SUPPRESS_AUDIO_RECORDING)
		// {
		// mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
		// }
		mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());

		try
		{
			mMediaRecorder.prepare();
		}
		catch (IOException exception)
		{
			releaseMediaRecorder();
			// TODO: add more exception handling logic here
			return false;
		}

		return true;
	}

	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height)
	{
		this.StopRecording();
		this.initializeVideo();
	}

	public void surfaceCreated(SurfaceHolder holder)
	{
		mSurfaceHolder = holder;
	}

	public void surfaceDestroyed(SurfaceHolder holder)
	{
		mSurfaceHolder = null;
	}


	public void onError(MediaRecorder mr, int what, int extra)
	{
		this.StopRecording();
	}


	public void onInfo(MediaRecorder mr, int what, int extra)
	{

	}
}

// ----------------------------------------------------------//

class Preview extends SurfaceView
{
	private float		mAspectRatio;
	private int			mHorizontalTileSize	= 1;
	private int			mVerticalTileSize	= 1;

	/**
	 * Setting the aspect ratio to this value means to not enforce an aspect
	 * ratio.
	 */
	public static float	DONT_CARE			= 0.0f;

	public Preview(Context context)
	{
		super(context);
	}

	public Preview(Context context, AttributeSet attrs)
	{
		super(context, attrs);
	}

	public Preview(Context context, AttributeSet attrs, int defStyle)
	{
		super(context, attrs, defStyle);
	}

	public void setTileSize(int horizontalTileSize, int verticalTileSize)
	{
		if ((mHorizontalTileSize != horizontalTileSize)	|| 
			(mVerticalTileSize   != verticalTileSize))
		{
			mHorizontalTileSize = horizontalTileSize;
			mVerticalTileSize = verticalTileSize;
			requestLayout();
			invalidate();
		}
	}

	public void setAspectRatio(int width, int height)
	{
		setAspectRatio(((float) width) / ((float) height));
	}

	public void setAspectRatio(float aspectRatio)
	{
		if (mAspectRatio != aspectRatio)
		{
			mAspectRatio = aspectRatio;
			requestLayout();
			invalidate();
		}
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
	{
		if (mAspectRatio != DONT_CARE)
		{
			int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
			int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);

			int width = widthSpecSize;
			int height = heightSpecSize;

			if (width > 0 && height > 0)
			{
				float defaultRatio = ((float) width) / ((float) height);
				if (defaultRatio < mAspectRatio)
				{
					// Need to reduce height
					height = (int) (width / mAspectRatio);
				}
				else if (defaultRatio > mAspectRatio)
				{
					width = (int) (height * mAspectRatio);
				}
				width = roundUpToTile(width, mHorizontalTileSize, widthSpecSize);
				height = roundUpToTile(height, mVerticalTileSize,
						heightSpecSize);
				setMeasuredDimension(width, height);
				return;
			}
		}
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	}

	private int roundUpToTile(int dimension, int tileSize, int maxDimension)
	{
		return Math.min(((dimension + tileSize - 1) / tileSize) * tileSize,
				maxDimension);
	}
}